#include "Game.h"

#include "PhysicsLogic.h"
#include "Sound.h"

Log Game::log;
Lensflare::Config Game::config;
Player Game::player[2];
int Game::currentPlayerIndex = 0;
bool Game::waitingForNextTurn = false;
bool Game::hudEnabled = true;
bool Game::helpViewEnabled = false;
bool Game::fpsEnabled = false;
int Game::winnerIndex = -1;
float Game::mouseSensivity = 16.0f;
bool Game::debugMode = false;

void Game::Init() {
	config.Get("DebugMode", debugMode);

	if(!debugMode) {
		log.SetLogLevel(Log::TARGET_CONSOLE, Log::LEVEL_INFO);
	}

	std::string name1;
	std::string name2;
	config.Get("PlayerName1", name1);
	config.Get("PlayerName2", name2);
	player[0].SetName(name1);
	player[1].SetName(name2);

	config.Get("MouseSensivity", mouseSensivity);

	player[0].areaCenterX = 24;
	player[1].areaCenterX = -24;
}

void Game::Reset(bool userFeedback) {
	if(userFeedback) {
		Sound::Play(Sound::SAMPLE_SCROLL, 0.5f);
	}

	winnerIndex = -1;

	PhysicsLogic::ClearScene();

	PhysicsLogic::CreateGround();

	for(int i=0; i<2; ++i) {
		currentPlayerIndex = i;
		player[i].Reset();
		player[i].PlaceHouses();
	}
	currentPlayerIndex = 0;

	Game::SetRandomWind();
}

void Game::Tick() {
	for(int i=0; i<2; ++i) {
		const bool noBuildingsLeft = player[i].GetBuildingsCount() <= 0;
		const bool noCannonsAndNoGold = player[i].cannons.Empty() && player[i].GetGold() < player[i].GetCosts(Player::PL_TOWER);
		if(noBuildingsLeft || noCannonsAndNoGold) {
			winnerIndex = (i == 0 ? 1 : 0);
			break;
		}
	}
}

void Game::SelectNextPlayer() {
	if(!WinnerEncountered()) {
		player[currentPlayerIndex].EndTurn();
		waitingForNextTurn = false;
		PhysicsLogic::SetCameraLocked(true);
		SetRandomWind();
		currentPlayerIndex = currentPlayerIndex == 0 ? 1 : 0;
		PhysicsLogic::HudMessage(StringBuilder() << player[currentPlayerIndex].GetName() << " ist dran.");
		Sound::Play(Sound::SAMPLE_SCROLL, 0.5f);
	}
}

void Game::SetRandomWind() {
	const int forceRange = 50;
	float v = float((rand()%(forceRange*2)) - forceRange);
	if(v == 0) {
		v = 0.01f;
	}
	PhysicsLogic::SetWind(NxVec3(v, 0, v));
}

void Game::ToggleHud() {
    hudEnabled = !hudEnabled;
}

void Game::ToggleHelpView() {
	helpViewEnabled = !helpViewEnabled;
}

void Game::ToggleFPS() {
    fpsEnabled = !fpsEnabled;
}

void Game::UserPlace() {
	Player* currentPlayer = GetCurrentPlayer();
	if(currentPlayer->IsPlacementAllowed()) {
		const int credit = currentPlayer->GetGold();
		const int costs = currentPlayer->GetCosts(currentPlayer->GetSelectedPlaceable());
		if(credit >= costs) {
			currentPlayer->PlaceSelectedPlaceable();
			currentPlayer->TakeGold(costs);
		} else {
			PhysicsLogic::HudMessage(StringBuilder() << "Nicht genug Gold für " << Player::GetNameOfPlacable(currentPlayer->GetSelectedPlaceable()));
		}
	} else {
		PhysicsLogic::HudMessage("Bauen hier nicht möglich!");
	}
}

void Game::UserClear() {
	Player* currentPlayer = Game::GetCurrentPlayer();
	NxVec3 pos = currentPlayer->GetPlacementBoxPosition();
	NxVec3 dim = currentPlayer->GetPlacementBoxDimension();
	dim.x -= 0.5f;
	dim.z -= 0.5f;
	NxBounds3 bounds;
	bounds.set(pos-dim, pos+dim);
	const int n = 1024;
	NxShape* shapes[n];
	int numberOfCollidedShapes = PhysicsLogic::GetScene()->overlapAABBShapes(bounds, NX_ALL_SHAPES, n, shapes, NULL);
	if(numberOfCollidedShapes > n) {
		numberOfCollidedShapes = n;
	}
	LinkedList<NxActor*> actors;
	for(int i=0; i<numberOfCollidedShapes; ++i) {
		NxActor* pickedActor = &shapes[i]->getActor();
		if(!actors.Contains(pickedActor)) {
			actors.Add(pickedActor);
		}
	}
	while(!actors.Empty()) {
		NxActor* pickedActor = actors.GetFirst();
		if(pickedActor->userData) {
			ActorEntity* actorEntity = (ActorEntity*)pickedActor->userData;
			if(actorEntity->GetType() == AET_CANNON_BALL) {
				CannonBall::toDelete.Add((CannonBall*)actorEntity);
			}
		} else {
			PhysicsLogic::DeleteNonEntityActor(pickedActor);
		}
		actors.RemoveFirst();
	}

	Sound::Play(Sound::SAMPLE_CLEAR, 0.5f, (pos-PhysicsLogic::GetCamera().GetPosition())*0.15f, PhysicsLogic::GetCameraForward());
}

void Game::UserShoot() {
	if(!waitingForNextTurn) {
		Player* currentPlayer = GetCurrentPlayer();
		Cannon* cannon = currentPlayer->GetSelectedCannon();
		if(cannon) {
			if(currentPlayer->GetExplosiveCannonBallsSelected()) {
				if(currentPlayer->GetGold() >= CannonBall::GetExplosionCosts()) {
					currentPlayer->TakeGold(CannonBall::GetExplosionCosts());
					cannon->Fire();
					PhysicsLogic::SetCameraLocked(false);
					Game::waitingForNextTurn = true;
				} else {
					PhysicsLogic::HudMessage("Nicht genug Gold für Explosivgeschoss");
				}
			} else {
				cannon->Fire();
				PhysicsLogic::SetCameraLocked(false);
				waitingForNextTurn = true;
			}
		}
	} else {
		PhysicsLogic::HudMessage("Kanone bereits abgefeuert. Bitte Zug beenden.");
	}
}
